<?php

/**
 * JingYao-backend
 *
 * @link     https://gitee.com/wang-zhihui-release/jingyao-backend
 * @apiDocument https://gitee.com/wang-zhihui-release/jingyao-backend/wikis/
 */

namespace App\Services;

use App\Enums\AdminActionTypeEnum;
use App\Enums\ArticleTypeEnum;
use App\Enums\HideOrShowEnum;
use App\Enums\IdentityVisibilityEnum;
use App\Enums\UserIdentityEnum;
use App\Exceptions\ApiException;
use App\Format\ArticleFormat;
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Storage;

class ArticleService
{
    const ONLY_ONE = [
        ArticleTypeEnum::ArticleTypeCompanyScore,
        ArticleTypeEnum::ArticleTypeScore,
        ArticleTypeEnum::ArticleTypePromise,
    ];

    protected $zhanXinPublicArticleService;

    protected $adminAuthService;

    public function __construct(ZhanXinPublicArticleService $zhanXinPublicArticleService, AdminAuthService $adminAuthService)
    {
        $this->zhanXinPublicArticleService = $zhanXinPublicArticleService;
        $this->adminAuthService = $adminAuthService;
    }

    public function getArticleListByType(int $type, $page = 1, $pageSize = 10, string $orderColumn = '', string $orderType = '', array $search = [], bool $isAdmin = false)
    {
        if ($type == ArticleTypeEnum::ArticleTypeZhanXin) {
            return $this->zhanXinPublicArticleService->getZhanxinArticlesList($page, $pageSize);
        }

        $builder = Article::query()->select('id', 'title', 'created_at', 'cover_url', 'push_time', 'identity_visibility', 'source', 'is_hide')
            ->where('type', $type);

        if ($type == ArticleTypeEnum::ArticleTypeDangZheng) {
            $builder = $this->typeDangZheng($builder);
        }
        if (! $isAdmin) {
            $builder->where('is_hide', HideOrShowEnum::SHOW);
        }

        if (isset($search['start_date'], $search['end_date'])) {
            $builder->where('push_time', '>=', strtotime($search['start_date']));
            if (strlen($search['end_date']) > 10) {
                $builder->where('push_time', '<=', strtotime($search['end_date']));
            } else {
                $builder->where('push_time', '<=', strtotime($search['end_date']) + (24 * 3600));
            }
        }
        if (isset($search['start_date']) && ! isset($search['end_date'])) {
            $builder->where('push_time', '>=', strtotime($search['start_date']));
        }
        if (! isset($search['start_date']) && isset($search['end_date'])) {
            if (strlen($search['end_date']) > 10) {
                $builder->where('push_time', '<=', strtotime($search['end_date']));
            } else {
                $builder->where('push_time', '<=', strtotime($search['end_date']) + (24 * 3600));
            }
        }

        if (isset($search['title']) && strlen($search['title']) > 0) {
            $builder->where('title', 'like', '%' . $search['title'] . '%');
        }
        if (strlen($orderColumn) > 0 && strlen($orderType) > 0) {
            $builder->orderBy($orderColumn, $orderType);
        }

        $count = $builder->count();

        $lists = $builder
            ->orderBy('created_at', 'desc')
            ->skip(($page - 1) * $pageSize)
            ->take($pageSize)
            ->get();

        return [
            'list' => $lists,
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
        ];
    }

    public function getArticleDeatil($id)
    {
        $article = Article::query()->find($id);
        if (empty($article)) {
            return [];
        }
        $type = $article->type;
        if (! in_array($type, config('public_article_type'))) {
            $userId = request('user_id');
            $token = request('token');
            if (! $userId || ! $token) {
                throw new ApiException('用户未登陆', config('error_code.no_login'));
            }
            $userService = new UserService();
            if (! $userService->checkLogin($userId, $token)) {
                throw new ApiException('用户未登陆', config('error_code.no_login'));
            }
        }
        $res = $article->toArray();

        if (! empty($article->image)) {
            $res['image'] = $article->image->toArray();
        }
        return $res;
    }

    public function searchArtices(string $title, int $page, int $pageSize)
    {
        $title = urldecode($title);
        $builder = Article::query()->where('title', 'like', '%' . $title . '%');
        $count = $builder->count();
        $list = $builder
            ->select('title', 'push_time', 'type', 'cover_url', 'id', 'content')
            ->orderByDesc('push_time')->skip(($page - 1) * $pageSize)->take($pageSize)->get();

        return [
            'page' => $page,
            'page_size' => $pageSize,
            'count' => $count,
            'list' => $list,
        ];
    }

    public function findVillagePromise()
    {
        return Article::query()->where('is_hide', HideOrShowEnum::SHOW)->where('type', ArticleTypeEnum::ArticleTypePromise)->first();
    }

    public function findScore()
    {
        return Article::query()->where('is_hide', HideOrShowEnum::SHOW)->where('type', ArticleTypeEnum::ArticleTypeScore)->first();
    }

    public function findCompanyScore()
    {
        return Article::query()->where('is_hide', HideOrShowEnum::SHOW)->where('type', ArticleTypeEnum::ArticleTypeCompanyScore)->first();
    }

    public function create(ArticleFormat $articleFormat)
    {
        if (in_array($articleFormat->getType(), self::ONLY_ONE)) {
            if (Article::query()->where('type', $articleFormat->getType())->exists()) {
                throw new ApiException(sprintf('%s 只能有一篇, 不能重复创建', ArticleTypeEnum::desc($articleFormat->getType())), 1);
            }
        }
        adminLog(new Article(), AdminActionTypeEnum::CREATE, '创建文章-' . ArticleTypeEnum::desc($articleFormat->getType()));
        Article::query()->create($articleFormat->toArrayNotNull());
        return true;
    }

    public function update(ArticleFormat $articleFormat)
    {
        $id = $articleFormat->getId();
        $article = Article::query()->find($id);
        // TODO 需要数据全量传递
        $article->update($articleFormat->toArray());
        return true;
    }

    public function delete(int $id)
    {
        adminLog(new Article(), AdminActionTypeEnum::DELETE, '删除文章');
        Article::query()->find($id)->delete();
        return true;
    }

    public function getArticleType(int $id)
    {
        /** @var null|Article $article */
        $article = Article::query()->select('type')->where('id', $id)->first();
        if (empty($article)) {
            throw new ApiException('文章不存在', 1);
        }
        return $article->type;
    }

    /**
     * @throws ApiException
     */
    public function checkArticleTypeAuth(int $userId, string $action, int $type): bool
    {
        // 获取用户的所有权限
        $userAuthActions = $this->adminAuthService->getUserRoleActions($userId)->toArray();
        $userAuthActionsMap = array_column($userAuthActions, null, 'action_desc');
        $auths = config('article_auth');
        foreach ($auths as $auth) {
            // type + action 可以确定唯一的一条数据
            // 如果这条数据中的 action_desc 在用户的权限列表中 那么用户就拥有这个权限
            if ($auth['type'] == $type && $auth['action'] == $action) {
                if (isset($userAuthActionsMap[$auth['action_desc']])) {
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    public function download(int $id)
    {
        /** @var null|Article $article */
        $article = Article::query()->find($id);
        if (empty($article)) {
            throw new ApiException('文章不存在', 1);
        }
        $name = date('Y-m-d-H:i:s', time()) . $article->title;
        $fileName = 'temp/download/' . $name . '.doc';
        $content = '<html
            xmlns:o="urn:schemas-microsoft-com:office:office"
            xmlns:w="urn:schemas-microsoft-com:office:word"
            xmlns="http://www.w3.org/TR/REC-html40">
            <meta charset="UTF-8" />' . $article->content . '</html>';

        Storage::put($fileName, $content);

        return $fileName;
    }

    public function hideOrShow(int $id, int $is_hide)
    {
        return Article::query()->where(['id' => $id])->update(['is_hide' => $is_hide]);
    }

    private function typeDangZheng(Builder $builder)
    {
        $userId = request()->input('user_id', null);
        if (empty($userId)) {
            $builder->where('identity_visibility', IdentityVisibilityEnum::ALL);
            return $builder;
        }
        /** @var null|User $user */
        $user = User::query()->select('identity')->find($userId);
        if (empty($user)) {
            $builder->where('identity_visibility', IdentityVisibilityEnum::ALL);
            return $builder;
        }
        if ($user->identity == UserIdentityEnum::FLOW_USER) {
            $builder->whereIn('identity_visibility', [IdentityVisibilityEnum::FLOW_USER, IdentityVisibilityEnum::ALL]);
            return $builder;
        }

        $builder->whereIn('identity_visibility', [IdentityVisibilityEnum::ALL, IdentityVisibilityEnum::NOT_FLOW]);
        return $builder;
    }

    private function checkArticleOperate(int $userId, int $type, string $action)
    {
        // 获取用户的所有权限
        $userAuthActions = $this->adminAuthService->getUserRoleActions($userId)->toArray();
        $userAuthActionsMap = array_column($userAuthActions, null, 'action_desc');
        $auths = config('article_auth');
        foreach ($auths as $auth) {
            if ($auth['type'] == $type && $auth['action'] == $action) {
                if (isset($userAuthActionsMap[$auth['action_desc']])) {
                    return true;
                }
                throw new ApiException('无权限', 1);
            }
        }
        throw new ApiException('系统错误', 1);
    }
}
